package cn.itcast.hotel;

import cn.itcast.hotel.pojo.HotelDoc;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.util.CollectionUtils;


import java.io.IOException;

import java.util.List;
import java.util.Map;

public class EsSearch {
    private RestHighLevelClient client;

    @BeforeEach
    void setUp() {
        this.client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://192.168.17.128:9200")
        ));
    }

    @AfterEach
    void tearDown() throws IOException {
        this.client.close();
    }
    @Test
    //按照品牌进行分组，打印每个分组的数量 和 每个分组的名称
    void aggregations() throws IOException {
        SearchRequest request = new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();
//        source.query(QueryBuilders.matchAllQuery());
        source.size(0);
        source.aggregation(
                AggregationBuilders.terms("brandAgg")
                        .field("brand")
                        .size(20)
        );

        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        Aggregations aggregations = response.getAggregations();
        Terms brand_agg = aggregations.get("brandAgg");
        List<? extends Terms.Bucket> buckets = brand_agg.getBuckets();
        for (Terms.Bucket bucket:buckets){
            System.out.println(bucket.getKey());
            System.out.println(bucket.getDocCount());
        }
    }
    @Test
    void highLight() throws IOException {
        //1.创建search requset 对象
        SearchRequest request = new SearchRequest("hotel");
        //1.1查询参数设置
        /**request.source().query()
         //                .from() .size
         //                .sort
         //                .highlight()
         */
        //在source中加条件
        SearchSourceBuilder source = request.source();
        source.query(QueryBuilders.matchQuery("name","外滩如家"));
        //1.1高亮参数设置
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name");
        highlightBuilder.preTags("<span>");
        highlightBuilder.postTags("</span>");
        source.highlighter(highlightBuilder);
        //2.请求执行
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //3.解析响应结果
        //获取文档总条数
        parsingHighLightDateTest(response);
    }

    /**
     *  分页排序
     */
    @Test
    void  sortAndPage() throws IOException {
        int page = 2;
        int size = 3;
        //创建请求
        SearchRequest request = new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();
        source.sort("score", SortOrder.DESC);
        source.sort("price", SortOrder.ASC);
        //设置分页参数
        source.from((page-1)*size);
        source.size(size);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        parsingDateTest(response);
    }
    /**
     * 布尔查询
     */
    @Test
    void booleanMatch() throws IOException {
        //1.创建search requset 对象
        SearchRequest request = new SearchRequest("hotel");
        //1.1设置请求参数
        /**request.source().query()
         //                .from() .size
         //                .sort
         //                .highlight()
         */
        SearchSourceBuilder source = request.source();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // 2.2.添加term
        boolQuery.must(QueryBuilders.matchQuery("name", "上海外滩"));
        // 2.3.添加range
        boolQuery.filter(QueryBuilders.rangeQuery("price").gte(500).lt(1000));
        //
        boolQuery.mustNot(QueryBuilders.termQuery("brand","万豪"));

        request.source().query(boolQuery);
        //2.请求执行
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //3.解析响应结果
        //获取文档总条数
        parsingDateTest(response);
    }
    /**
     * 范围查询
     */
    @Test
    void termMatch() throws IOException {
        //1.创建search requset 对象
        SearchRequest request = new SearchRequest("hotel");
        //1.1设置请求参数
        /**request.source().query()
         //                .from() .size
         //                .sort
         //                .highlight()
         */
        SearchSourceBuilder source = request.source();
        source.query(QueryBuilders.termQuery("city","杭州"));
        //2.请求执行
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //3.解析响应结果
        //获取文档总条数
        parsingDateTest(response);
    }
    /**
     * 分词查询
     */
    @Test
    void match() throws IOException {
        //1.创建search requset 对象
        SearchRequest request = new SearchRequest("hotel");
        //1.1设置请求参数
        /**request.source().query()
         //                .from() .size
         //                .sort
         //                .highlight()
         */
        SearchSourceBuilder source = request.source();
        source.query(QueryBuilders.matchQuery("name","如家外滩"));
        //2.请求执行
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //3.解析响应结果
        //获取文档总条数
       parsingHighLightDateTest(response);
    }
    /**
     * 查询所有
     * @throws IOException
     */
    @Test
    void searchAll() throws IOException {
        //1.创建search requset 对象
        SearchRequest request = new SearchRequest("hotel");
        //1.1设置请求参数
        /**request.source().query()
        //                .from() .size
        //                .sort
        //                .highlight()
         */
        SearchSourceBuilder source = request.source();
        source.query(QueryBuilders.matchAllQuery());
        //2.请求执行
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //3.解析响应结果
        //获取文档总条数
       parsingDateTest(response);
    }
    /**
     * 解析工作类
     */
    void parsingDateTest(SearchResponse response){
        //3.解析响应结果
        //获取文档总条数
        SearchHits hits = response.getHits();

        System.out.println(hits.getTotalHits().value);
        //获取文档列表
        SearchHit[] hitsHits = hits.getHits();
        for (SearchHit s:hitsHits){
            String string = s.getSourceAsString();
            HotelDoc doc = JSON.parseObject(string, HotelDoc.class);
            System.out.println(doc);
        }
    }
    void parsingHighLightDateTest(SearchResponse response){
        //3.解析响应结果
        //获取文档总条数
        SearchHits hits = response.getHits();

        System.out.println("查询的文档数量 " + hits.getTotalHits().value);
        for (SearchHit s:hits){
            String string = s.getSourceAsString();
            HotelDoc hotelDoc = JSON.parseObject(string, HotelDoc.class);
            Map<String, HighlightField> highlightFields = s.getHighlightFields();
            if (!CollectionUtils.isEmpty(highlightFields)){
                HighlightField highlightField = highlightFields.get("name");
                String s1 = StringUtils.join(highlightField.getFragments());
                hotelDoc.setName(s1);
            }
            System.out.println(hotelDoc);
        }
    }
}
